/**
 * 
 */
package cc.dogtailflower.framework.basedao;

import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import cc.dogtailflower.framework.HelperLoader;
import cc.dogtailflower.framework.bean.Page;
import cc.dogtailflower.framework.datasource.SimpleDataSource;
import cc.dogtailflower.framework.resultsetmapper.ResultSetMapperImpl;
import cc.dogtailflower.framework.resultsetmapper.ResultSetMapperNoClassImpl;
import cc.dogtailflower.framework.resultsetmapper.ResultSetObjectMappingTable;

/**
 * @author cc
 *
 */
public class BaseDao<T> extends JdbcOperationImpl<T>{
		
	static{
		HelperLoader.allocAndInit();
	}
	
	public BaseDao(){
		setDataSource(SimpleDataSource.getInstance());
	}


	public int insert(T dmo){
		
		int row = 0;
		Class<?> clazz = dmo.getClass();
		String tableName = ResultSetObjectMappingTable.getTableMap().get(clazz);
		String sql = "INSERT INTO "+tableName+" VALUES (";
		Method[] methods = clazz.getDeclaredMethods();
		List<Object> paramsList = new ArrayList<Object>();
		
		for(Method method:methods){
			if(method.getName().startsWith("get")){
				try {
					Object result = method.invoke(dmo);
					String param = (result == null ? null : "?");
					sql+=param+" ,";
					if(result != null){
						paramsList.add(result);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		int length = sql.length();
		sql = sql.substring(0,length-1);
		sql+=");";
		Object[] params = paramsList.toArray();
		
		try {
			row = this.execute(sql, params);
		} catch (SQLException e) {
	
			e.printStackTrace();
		}
		return row;
	}
	
	public int update(T dmo){
		
		int row = 0;
		Class<?> clazz = dmo.getClass();
		String tableName = ResultSetObjectMappingTable.getTableMap().get(clazz);
		Map<String,String> fieldMap =  ResultSetObjectMappingTable.getReMap().get(tableName);
		String keyField = ResultSetObjectMappingTable.getKeyMap().get(clazz);
		String sql = "UPDATE "+tableName+" SET ";
		String where = "";
		Method[] methods = clazz.getDeclaredMethods();
		List<Object> paramsList = new ArrayList<Object>();
		
		for(Method method:methods){
			if(method.getName().startsWith("get")){
				try {
					Object result = method.invoke(dmo);
					if(result != null){
						String methodName = method.getName().substring(3);
						String pre = methodName.substring(0, 1);
						pre = pre.toLowerCase();
						methodName = pre+methodName.substring(1);
						String column = fieldMap.get(methodName);
						if(methodName.equals(keyField)){
							where += " WHERE " + column +" = "+result;
							continue;
						}
						column+=" = ? AND ";
						sql+=column;
						paramsList.add(result);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		int length = sql.length();
		sql = sql.substring(0,length-4);
		sql+=where;
		sql+=";";
		Object[] params = paramsList.toArray();
		
		try {
			row = this.execute(sql, params);
		} catch (SQLException e) {
	
			e.printStackTrace();
		}
		return row;
	}
	
	
	public int delete(T dmo){

		int row = 0;
		Class<?> clazz = dmo.getClass();
		String tableName = ResultSetObjectMappingTable.getTableMap().get(clazz);
		Map<String,String> fieldMap =  ResultSetObjectMappingTable.getReMap().get(tableName);
		String sql = "DELETE FROM "+tableName+" WHERE ";
		Method[] methods = clazz.getDeclaredMethods();
		List<Object> paramsList = new ArrayList<Object>();
		
		for(Method method:methods){
			if(method.getName().startsWith("get")){
				try {
					Object result = method.invoke(dmo);
					if(result != null){
						String methodName = method.getName().substring(3);
						String pre = methodName.substring(0, 1);
						pre = pre.toLowerCase();
						methodName = pre+methodName.substring(1);
						String column = fieldMap.get(methodName);
						column+=" = ? AND ";
						sql+=column;
						paramsList.add(result);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		int length = sql.length();
		sql = sql.substring(0,length-4);
		sql+=";";
		Object[] params = paramsList.toArray();
		
		try {
			row = this.execute(sql, params);
		} catch (SQLException e) {
	
			e.printStackTrace();
		}
		return row;
	}
	
	public T selectOne(T dmo){
		
		if(this.selectCount(dmo) > 1){
			throw new RuntimeException("at most one!!!");
		}
		List<T> list = this.selectList(dmo);
		if(list.size() != 0){
			return list.get(0);
		}
		return null;
	}
	
	public List<T> selectList(T dmo){
	
		Class<?> clazz = dmo.getClass();
		String tableName = ResultSetObjectMappingTable.getTableMap().get(clazz);
		Map<String,String> fieldMap =  ResultSetObjectMappingTable.getReMap().get(tableName);
		String sql = "SELECT * FROM "+tableName+" WHERE ";
		Method[] methods = clazz.getDeclaredMethods();
		List<Object> paramsList = new ArrayList<Object>();
		
		for(Method method:methods){
			if(method.getName().startsWith("get")){
				try {
					Object result = method.invoke(dmo);
					if(result != null){
						String methodName = method.getName().substring(3);
						String pre = methodName.substring(0, 1);
						pre = pre.toLowerCase();
						methodName = pre+methodName.substring(1);
						String column = fieldMap.get(methodName);
						column+=" = ? AND ";
						sql+=column;
						paramsList.add(result);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		int length = sql.length();
		sql = sql.substring(0,length-4);
		sql+=";";
		Object[] params = paramsList.toArray();
		List<T> list = null;;
		try {
			list = this.queryForBean(sql, params, new ResultSetMapperImpl<T>(),clazz);
			
		} catch (SQLException e) {

			e.printStackTrace();
		}
		return list;
	}
	
	public int selectCount(T dmo){
		
		int row = 0;
		Class<?> clazz = dmo.getClass();
		String tableName = ResultSetObjectMappingTable.getTableMap().get(clazz);
		Map<String,String> fieldMap =  ResultSetObjectMappingTable.getReMap().get(tableName);
		String sql = "SELECT COUNT(*) FROM "+tableName+" WHERE ";
		Method[] methods = clazz.getDeclaredMethods();
		List<Object> paramsList = new ArrayList<Object>();
		
		for(Method method:methods){
			if(method.getName().startsWith("get")){
				try {
					Object result = method.invoke(dmo);
					if(result != null){
						String methodName = method.getName().substring(3);
						String pre = methodName.substring(0, 1);
						pre = pre.toLowerCase();
						methodName = pre+methodName.substring(1);
						String column = fieldMap.get(methodName);
						column+=" = ? AND ";
						sql+=column;
						paramsList.add(result);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		int length = sql.length();
		sql = sql.substring(0,length-4);
		sql+=";";
		Object[] params = paramsList.toArray();
		
		try {
			row = this.queryForInt(sql, params);
		} catch (SQLException e) {
	
			e.printStackTrace();
		}
		return row;
	}
	
	public List<T> selectListByPage(T dmo,Page page){
		Class<?> clazz = dmo.getClass();
		String tableName = ResultSetObjectMappingTable.getTableMap().get(clazz);
		Map<String,String> fieldMap =  ResultSetObjectMappingTable.getReMap().get(tableName);
		String sql = "SELECT * FROM "+tableName+" WHERE ";
		Method[] methods = clazz.getDeclaredMethods();
		List<Object> paramsList = new ArrayList<Object>();
		
		for(Method method:methods){
			if(method.getName().startsWith("get")){
				try {
					Object result = method.invoke(dmo);
					if(result != null){
						String methodName = method.getName().substring(3);
						String pre = methodName.substring(0, 1);
						pre = pre.toLowerCase();
						methodName = pre+methodName.substring(1);
						String column = fieldMap.get(methodName);
						column+=" = ? AND ";
						sql+=column;
						paramsList.add(result);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		int length = sql.length();
		sql = sql.substring(0,length-4);
		//分页Limit
		String limit = " LIMIT ";
		limit+=(page.getCurrentPage()-1)*page.getPageSize() +" , "+page.getPageSize();
		sql+=limit+";";
		Object[] params = paramsList.toArray();
		List<T> list = null;;
		try {
			list = this.queryForBean(sql, params, new ResultSetMapperImpl<T>(),clazz);
			
		} catch (SQLException e) {

			e.printStackTrace();
		}
		return list;
	}

	@SuppressWarnings("unchecked")
	public List<Map<String,Object>> selectListBySql(String sql,Object... obj){
		
		List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
		try {
			List<T> resultList = this.queryForResultSet(sql, obj,new ResultSetMapperNoClassImpl<T>());
			for(T l : resultList){
				Map<String,Object> m = (Map<String,Object>)l;
				list.add(m);
			}
			
		} catch (SQLException e) {
	
			e.printStackTrace();
		}
		return list;
	}

}
